package edu.uwm.RobberKnight.View;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JSeparator;
import javax.swing.border.LineBorder;
import javax.swing.filechooser.FileFilter;

import edu.uwm.RobberKnight.Controller.RobberKnightsController;
import edu.uwm.RobberKnight.Model.Tile;


import java.awt.Color;
import java.io.File;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.Box;

/*
 * The main window for the Robber Knights game.
 */
public class GameView {

    private JFrame _frmRobberKnights;
    private StatusPanel _status;
    private RobberKnightsController _controller;
    private SetUpView _setUpView;
    private BoardView _boardView;
    private InstructionView _iView;
    private JPanel _pnlGame;
    private HelpView _helpView;
    private AboutView _aboutView;
    private JMenuItem mntmSaveGame;
    private boolean instruction = false;
    private boolean about = false;
    private boolean fullScreen = false;
    private Color bgColor = new Color(255,255,255);
    private JColorChooser colorChooser;
    private JFileChooser fc;
    private Component _beforeFileChooser;
    private boolean _saving;
    private boolean _loading;
    
    /**
     * Create the application.
     */
    public GameView() {
        _controller = new RobberKnightsController();
        Resources.loadResources();
        initialize();
        _frmRobberKnights.setVisible(true);
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        _frmRobberKnights = new JFrame();
        _frmRobberKnights.setMinimumSize(new Dimension(900, 600));
        _frmRobberKnights.setTitle("Robber Knights");
        _frmRobberKnights.setBounds(100, 100, 450, 300);
        _frmRobberKnights.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        _frmRobberKnights.setIconImage(Resources.getTitleIcon());
        final GraphicsDevice gd = getDefaultGraphicsDevice();

        JMenuBar menuBar = new JMenuBar();
        _frmRobberKnights.setJMenuBar(menuBar);

        JMenu mnFile = new JMenu("File");
        menuBar.add(mnFile);

        JMenuItem mntmNewGame = new JMenuItem("New Game");
        mntmNewGame.addMouseListener(new MouseAdapter() {

        	/*
        	 * Set up a new game.
        	 */
            @Override
            public void mouseReleased(MouseEvent e) {
                //Remove boards and setup screen if it exits
                for (Component comp : _pnlGame.getComponents()) {
                    if (comp.equals(_setUpView)) {
                        _pnlGame.remove(_setUpView);
                    }
                    if (comp.equals(_boardView)) {
                        _pnlGame.remove(_boardView);
                    }
                }
                _boardView = null;
                _controller.newGame();
                _setUpView.setFinished(false);
                _setUpView = new SetUpView(_controller);
                _pnlGame.add(_setUpView, BorderLayout.CENTER);
                _frmRobberKnights.validate();
            }
        });
        mnFile.add(mntmNewGame);
    	fc = new JFileChooser(new File("."));
    	fc.addChoosableFileFilter(new FileFilter() {
			
			@Override
			public String getDescription() {
				return "File type: .rk";
			}
			
			@Override
			public boolean accept(File file) {
				return (file.isDirectory() || file.getName().contains(".rk"));
			}
		});
    	fc.addActionListener(new ActionListener() {

    		/*
    		 * Handle the click of a file chooser for a save or load game event.
    		 */
			public void actionPerformed(ActionEvent evt) {
				if(evt.getActionCommand() == JFileChooser.APPROVE_SELECTION) {
					if(_loading) {
						loadGame(fc.getSelectedFile());
					} else if (_saving) {
						saveGame(fc.getSelectedFile());
					}
				} else if (evt.getActionCommand() == JFileChooser.CANCEL_SELECTION) {
					_loading = false;
					_saving = false;
					_pnlGame.remove(fc);
					_pnlGame.add(_beforeFileChooser);
				}
			}
    	});
        mntmSaveGame = new JMenuItem("Save Game");
        mntmSaveGame.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
            	_saving = true;
            	fc.setApproveButtonText("Save");
            	showFileChooser();
            }
		});
        
        JMenuItem mntmLoadGame = new JMenuItem("Load Game");
        mntmLoadGame.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
            	_loading = true;
            	fc.setApproveButtonText("Open");
            	showFileChooser();
            }
		});
        mnFile.add(mntmLoadGame);
        mnFile.add(mntmSaveGame);

        
        JMenu mnView = new JMenu("View");
        final JMenuItem mntmFullScreen = new JMenuItem("Full Screen");
        final JMenuItem mntmExitFullScreen = new JMenuItem("Exit Full Screen");
        mntmExitFullScreen.setEnabled(false);
        mntmFullScreen.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
				if (gd != null && gd.isFullScreenSupported() && !fullScreen) {
                    fullScreen = !fullScreen;
                    gd.setFullScreenWindow(_frmRobberKnights);
                    mntmExitFullScreen.setEnabled(true);
                    mntmFullScreen.setEnabled(false);
                }
            }
        });
        mntmExitFullScreen.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
				if (gd != null && gd.isFullScreenSupported() && fullScreen) {
                    fullScreen = !fullScreen;
                    gd.setFullScreenWindow(null);
                    mntmExitFullScreen.setEnabled(false);
                    mntmFullScreen.setEnabled(true);
                }
            }
        });

        mnView.add(mntmFullScreen);
        mnView.add(mntmExitFullScreen);
        
        final JMenu mntmColor= new JMenu("Background color");
    	bgColor = _frmRobberKnights.getBackground();
    	colorChooser = new JColorChooser(bgColor);
    	colorChooser.setPreviewPanel(new JPanel());
    	mntmColor.add(colorChooser);
    	mnView.add(mntmColor);
        menuBar.add(mnView);

        JMenuItem mntmExit = new JMenuItem("Exit");
        mntmExit.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                System.exit(0);
            }
        });

        JSeparator separator = new JSeparator();
        mnFile.add(separator);
        mnFile.add(mntmExit);

        JMenu mnHelp = new JMenu("Help");
        menuBar.add(mnHelp);

        JMenuItem mntmFSIcon = new JMenuItem(new ImageIcon(Resources.getFullscreenIcon()));
        mntmFSIcon.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        mntmFSIcon.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
				if (gd != null && gd.isFullScreenSupported()) {
					if (!fullScreen) {
						gd.setFullScreenWindow(_frmRobberKnights);
						mntmExitFullScreen.setEnabled(true);
						mntmFullScreen.setEnabled(false);
					} else {
						gd.setFullScreenWindow(null);
						mntmExitFullScreen.setEnabled(false);
						mntmFullScreen.setEnabled(true);
					}
					fullScreen = !fullScreen;

				}
			}
        });

        Component horizontalStrut = Box.createHorizontalStrut(656);
        menuBar.add(horizontalStrut);
        menuBar.add(mntmFSIcon);
        JMenuItem mntmInstructions = new JMenuItem("Instructions");
        mntmInstructions.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                flipInstructionPanel();
            }
        });
        mnHelp.add(mntmInstructions);

        JMenuItem mntmAbout = new JMenuItem("About");
        mntmAbout.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                flipAboutPanel();
            }
        });
        mnHelp.add(mntmAbout);
        _frmRobberKnights.getContentPane().setLayout(new BorderLayout(0, 0));

        _status = new StatusPanel(_controller, this);
        _status.setPreferredSize(new Dimension(290, 600));
        _status.setBorder(new LineBorder(new Color(0, 0, 0)));
        _frmRobberKnights.getContentPane().add(_status, BorderLayout.EAST);

        _iView = new InstructionView(_controller);
        _iView.setBorder(new LineBorder(new Color(0, 0, 0)));
        _frmRobberKnights.getContentPane().add(_iView, BorderLayout.NORTH);
        GroupLayout gl__iView = new GroupLayout(_iView);
        gl__iView.setHorizontalGroup(
                gl__iView.createParallelGroup(Alignment.LEADING).addGap(0, 782, Short.MAX_VALUE));
        gl__iView.setVerticalGroup(
                gl__iView.createParallelGroup(Alignment.LEADING).addGap(0, 24, Short.MAX_VALUE));
        _iView.setLayout(gl__iView);

        _pnlGame = new JPanel();
        _pnlGame.setPreferredSize(new Dimension(600, 600));
        _pnlGame.setMinimumSize(new Dimension(500, 500));
        _frmRobberKnights.getContentPane().add(_pnlGame, BorderLayout.CENTER);
        _pnlGame.setLayout(new BorderLayout(0, 0));

        _setUpView = new SetUpView(_controller);
        _pnlGame.add(_setUpView, BorderLayout.CENTER);

        _helpView = new HelpView();
        JButton closeHelp = new JButton("Close");
        closeHelp.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                flipInstructionPanel();
            }
        });
        _helpView.add(closeHelp);
        _helpView.setBounds(0, 0, 500, 300);
        _helpView.setVisible(false);

        _aboutView = new AboutView();
        JButton closeAbout = new JButton("Close");
        closeAbout.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                flipAboutPanel();
            }
        });
        _aboutView.add(closeAbout);
        _aboutView.setBounds(0, 0, 500, 300);
        _aboutView.setVisible(false);

    }
    private long _timeLastFrame;

    /*
     * The game loop, updates the state of the game and redraws the GUI as necessary.
     */
    public void runGame() {
        _timeLastFrame = System.currentTimeMillis();
        while (true) {
            long interval = System.currentTimeMillis() - _timeLastFrame;
            bgColor = colorChooser.getColor();
            //check inputs

            //update state
            if (_boardView != null) {
                _boardView.updateState(interval);
                _boardView.setBackground(bgColor);
            	mntmSaveGame.setVisible(true);
            } else {
            	mntmSaveGame.setVisible(false);
            }
            
            if(!_setUpView.isFinished()){
                _setUpView.setBackground(bgColor);
            }
            _aboutView.setBackground(bgColor);
            _helpView.setBackground(bgColor);
            _status.setBackground(bgColor);
            _status.updateState(interval);

            //redraw
            _frmRobberKnights.repaint();
            _iView.setBackground(bgColor);
            _iView.refresh();
            _timeLastFrame = System.currentTimeMillis();

            try {
                Thread.sleep(25);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (instruction) {
                _helpView.setVisible(true);
            } else {
                _helpView.setVisible(false);
            }

            if (about) {
                _aboutView.setVisible(true);
            } else {
                _aboutView.setVisible(false);
            }
            if (_boardView == null && _setUpView.isFinished()) {
                _boardView = new BoardView(_controller);
                _pnlGame.remove(_setUpView);
                _pnlGame.add(_boardView, BorderLayout.CENTER);
                _frmRobberKnights.validate();
                _boardView.centerScreen();
            }
        }
    }

    /*
     * Show or hide the instruction panel.
     */
    private void flipInstructionPanel() {
        if (!instruction) {
            about = false;
            _helpView.openInst();
            if (_setUpView != null) {
                _pnlGame.remove(_setUpView);
            }
            if (_boardView != null) {
                _pnlGame.remove(_boardView);
            }
            if (_aboutView != null) {
                _pnlGame.remove(_aboutView);
            }
            _pnlGame.add(_helpView);
        } else {
            if (_setUpView != null && !_setUpView.isFinished()) {
                _pnlGame.add(_setUpView);
            } else if (_boardView != null) {
                _pnlGame.add(_boardView);
            }
            _pnlGame.remove(_helpView);
        }
        instruction = !instruction;
    }

    /*
     * Show or hide the about panel.
     */
    private void flipAboutPanel() {
        if (!about) {
            instruction = false;
            _aboutView.openInst();
            if (_setUpView != null) {
                _pnlGame.remove(_setUpView);
            }
            if (_boardView != null) {
                _pnlGame.remove(_boardView);
            }
            if (_helpView != null) {
                _pnlGame.remove(_helpView);
            }
            _pnlGame.add(_aboutView);
        } else {
            if (_setUpView != null && !_setUpView.isFinished()) {
                _pnlGame.add(_setUpView);
            } else if (_boardView != null) {
                _pnlGame.add(_boardView);
            }
            _pnlGame.remove(_aboutView);
        }
        about = !about;
    }
    
    /*
     * Show the file chooser.
     */
    private void showFileChooser() {
    	if(_pnlGame.getComponentCount() > 0 && _pnlGame.getComponent(0) != fc) {
    		_beforeFileChooser = _pnlGame.getComponent(0);
    		_pnlGame.remove(_beforeFileChooser);
    	}
    	fc.rescanCurrentDirectory();
    	_pnlGame.add(fc);
    	_pnlGame.revalidate();
    }
    
    private void loadGame(File selFile) {
		if (selFile != null) {
			if (_controller.loadState(selFile.getAbsolutePath())) {
				_pnlGame.removeAll();
				_setUpView.setFinished(true);
				_boardView = new BoardView(_controller);
				_pnlGame.add(_boardView, BorderLayout.CENTER);
				_frmRobberKnights.validate();
				_boardView.centerScreen();
			} else {
				return;
			}
		}
		_loading = false;
    }
    
    private void saveGame(File selFile) {
    	if(selFile !=null) {
    		if(!selFile.getName().endsWith(".rk"))
    			selFile = new File(selFile.getAbsolutePath() +".rk");
    		_controller.saveState(selFile.getAbsolutePath());
    		_pnlGame.remove(fc);
    		_pnlGame.add(_beforeFileChooser);
    	}
    }
    
    /*
     * Set the display tile on the board view.
     */
    public void setDisplayTile(Tile tile) {
    	_boardView.setDisplayTile(tile);
    }
    
    private GraphicsDevice getDefaultGraphicsDevice() {
		try {
			return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
		} catch (HeadlessException e) {
			return null;
		}
	}
}
